use crate::core::{common::Sex, db_base::get_conn};
use anyhow::Result;
use sqlx::Row;
use sqlx::mysql::MySqlRow;

#[derive(Debug,serde::Serialize,serde::Deserialize)]
pub(crate) struct Teacher {
    pub(crate) id: u32,
    pub(crate) create_time: time::PrimitiveDateTime,
    pub(crate) name: String,
    pub(crate) sex: Sex,
    pub(crate) age: u8,
    pub(crate) email: String,
    pub(crate) remark: Option<String>,
}

impl Teacher {
    pub async fn find_by_name(name: impl AsRef<str>) -> Result<Option<Self>> {
        let conn = get_conn().await?;
        let teacher = sqlx::query(
            "SELECT id,create_time,name,sex,age,email,remark FROM teacher WHERE name=?;",
        )
        .bind(name.as_ref())
        .map(Self::map_row)
        .fetch_optional(&conn)
        .await?;
        Ok(teacher)
    }
    fn map_row(row: MySqlRow) -> Self {
        let sex = row.get::<u8, &str>("sex").try_into().unwrap();
        Self {
            id: row.get("id"),
            create_time: row.get("create_time"),
            name: row.get("name"),
            sex: sex,
            age: row.get("age"),
            email: row.get("email"),
            remark: row.get("remark"),
        }
    }
    pub async fn fetch_all(
        name: impl AsRef<str>,
        page_index: u8,
        page_size: u8,
    ) -> Result<Vec<Self>> {
        let conn = get_conn().await?;
        let start_index = (page_index - 1) * page_size;
        let query = if name.as_ref().is_empty() {
            sqlx::query("SELECT id,create_time,name,sex,age,email,remark FROM teacher limit ?, ?;")
                .bind(start_index)
                .bind(page_size)
        } else {
            sqlx::query( "SELECT id,create_time,name,sex,age,email,remark FROM teacher WHERE name=? limit ?, ?;")
            .bind(name.as_ref()).bind(start_index).bind(page_size)
        };
        let teachers = query.map(Self::map_row).fetch_all(&conn).await?;
        Ok(teachers)
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[actix_web::test]
    async fn teacher_fetch_all_test() -> Result<()> {
        let teachers = Teacher::fetch_all("", 1, 10).await;
        assert!(teachers.is_ok());
        if let Ok(teachers) = teachers {
            assert!(teachers.len() > 0);
            teachers.iter().for_each(|t| println!("{:#?}",t));
        }
        Ok(())
    }
}
